﻿using System;
using System.Collections.Generic;
using System.Drawing;
using EmbeddedSharp.Core;
using EmbeddedSharp.Scripting;
using Zove.Scripting.Core.Functions;

namespace EmbeddedSharp.Scripting.Visualization.Functions
{
    public enum CurveMode
    {
        Line = 0,
        Discreet
    }

    public enum FillMode
    {
        None = 0,
        Above,
        Below
    }

    /// <summary>
    /// Pick a color randomly.
    /// </summary>
    public class RandomColorPicker
    {
        /// <summary>
        /// Pick a color randomly.
        /// </summary>
        /// <returns></returns>
        public static Color Pick()
        {
            var ran = new Random();
            int random = ran.Next(1, 10);

            switch (random)
            {
                case 1:
                    return Color.Black;
                case 2:
                    return Color.White;
                case 3:
                    return Color.Brown;
                case 4:
                    return Color.Red;
                case 5:
                    return Color.Yellow;
                case 6:
                    return Color.Green;
                case 7:
                    return Color.Orange;
                case 8:
                    return Color.Olive;
                case 9:
                    return Color.Ivory;
                default:
                    return Color.Coral;
            }

            return Color.SkyBlue;
        }
    }

    /// <summary>
    /// Syntax:
    /// plot(function, arg, start, end
    ///    [, title, xAxisLabel, yAxisLabel, curveMode, fillMode]);
    /// 
    /// Example:
    /// plot(x+2, x, 0, 100, "x+2");
    /// </summary>
    public class PlotNode : VisualizationContextFuncNode
    {
        protected readonly List<IUnaryParameterFunction> functions
            = new List<IUnaryParameterFunction>();

        protected CurveMode curveMode;

        protected FillMode fillMode;

        protected double from;

        protected string title = string.Empty;

        protected double to;

        private string xAxisLabel, yAxisLabel;

        public PlotNode()
        {
            base.Value = "plot";
        }

        public override object Evaluate()
        {
            int count = Parameters.Count;

            if (count < 4)
            {
                throw new ArgumentException(
                    "usage: plot(function, variable, start, end[, title])");
            }

            from = Convert.ToDouble(Parameters[count - 3].Evaluate());
            to = Convert.ToDouble(Parameters[count - 4].Evaluate());

            // default settings
            curveMode = CurveMode.Line;
            fillMode = FillMode.None;

            if (count > 5)
            {
                title = Convert.ToString(Parameters[count - 5].Evaluate());
            }
            else if (count > 6)
            {
                xAxisLabel = Convert.ToString(Parameters[count - 6].Evaluate());
            }
            else if (count > 7)
            {
                yAxisLabel = Convert.ToString(Parameters[count - 7].Evaluate());
            }
            else if (count > 8)
            {
                curveMode = (CurveMode) Convert.ToInt32(
                    Parameters[count - 8].Evaluate());
            }
            else if (count > 9)
            {
                fillMode = (FillMode) Convert.ToInt32(
                    Parameters[count - 9].Evaluate());
            }

            object obj = Parameters[count - 2].Evaluate();
            if (obj == null)
            {
                throw new NullReferenceException(
                    "The parameter " + Parameters[count - 2].Value + " is null!");
            }

            string var = Parameters[count - 2].Value;
            if (Parameters[count - 1] is ListNode)
            {
                var ln = Parameters[count - 1] as ListNode;
                foreach (Node n in ln.Parameters)
                {
                    IUnaryParameterFunction func = ProcessExpression(var, n);
                    functions.Add(func);
                }
            }
            else
            {
                IUnaryParameterFunction func = ProcessExpression
                    (var, Parameters[count - 1]);
                functions.Add(func);
            }

            if (count < 5)
            {
                // TODO change the 
                title = string.Empty;
            }

            Provider.AddCurves(functions.ToArray(), from, to);

            return string.Empty;
        }

        private IUnaryParameterFunction ProcessExpression(string var, Node node)
        {
            string expr = string.Empty;

            if (node is FormulateNode)
            {
                expr = Convert.ToString(node.Evaluate());
            }
            else if (node is FuncNode)
            {
                var csct
                    = new DefaultExpressionTranslator();
                expr = csct.Translate(node);
            }
            else if (node is VariableNode)
            {
                var fn = node.Evaluate() as FuncNode;
                if (fn == null)
                {
                    throw new ArgumentException(
                        "The first parameter should be a function.");
                }
                var csct
                    = new DefaultExpressionTranslator();
                expr = csct.Translate(node);
            }

            IUnaryParameterFunction func
                = Context.UnaryFunctionFactory.Create(var, expr);

            return func;
        }
    }
}